<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>mysql-index | 静待花开</title><meta name="author" content="brad 随风起舞"><meta name="copyright" content="brad 随风起舞"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="mysql 的索引学习.mysql的索引搜索是从最左边的前缀开始的,所以定义索引的列的顺序很重要. 索引类型B-Tree indexes当人们谈论索引没有提及索引类型的时候,基本上都是在谈论B-Tree索引,这种索引使用B-Tree数据结构储存数据.InnoDB存储引擎使用B+Trees.MyISAM存储引擎使用一种前缀表达式技术使得索引更小,但是InnoDB在索引留下了未被压缩的值.MyISAM">
<meta property="og:type" content="article">
<meta property="og:title" content="mysql-index">
<meta property="og:url" content="https://zhangbo4881820.gitee.io/myblog/posts/17440/index.html">
<meta property="og:site_name" content="静待花开">
<meta property="og:description" content="mysql 的索引学习.mysql的索引搜索是从最左边的前缀开始的,所以定义索引的列的顺序很重要. 索引类型B-Tree indexes当人们谈论索引没有提及索引类型的时候,基本上都是在谈论B-Tree索引,这种索引使用B-Tree数据结构储存数据.InnoDB存储引擎使用B+Trees.MyISAM存储引擎使用一种前缀表达式技术使得索引更小,但是InnoDB在索引留下了未被压缩的值.MyISAM">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png">
<meta property="article:published_time" content="2019-11-14T09:26:21.000Z">
<meta property="article:modified_time" content="2023-09-07T09:44:01.893Z">
<meta property="article:author" content="brad 随风起舞">
<meta property="article:tag" content="mysql">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png"><link rel="shortcut icon" href="/myblog/img/favicon.png"><link rel="canonical" href="https://zhangbo4881820.gitee.io/myblog/posts/17440/index.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/myblog/css/index.css"><link rel="stylesheet" href="/myblog/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="/myblog/css/fancybox.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = {
  root: '/myblog/',
  algolia: undefined,
  localSearch: {"path":"/myblog/search.xml","preload":false,"top_n_per_article":1,"unescape":false,"languages":{"hits_empty":"找不到您查询的内容：${query}","hits_stats":"共找到 ${hits} 篇文章"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  dateSuffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false,
  percent: {
    toc: true,
    rightside: false,
  },
  autoDarkmode: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'mysql-index',
  isPost: true,
  isHome: false,
  isHighlightShrink: true,
  isToc: true,
  postUpdate: '2023-09-07 17:44:01'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
    win.getCSS = (url,id = false) => new Promise((resolve, reject) => {
      const link = document.createElement('link')
      link.rel = 'stylesheet'
      link.href = url
      if (id) link.id = id
      link.onerror = reject
      link.onload = link.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        link.onload = link.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(link)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><meta name="generator" content="Hexo 7.0.0-rc2"><link rel="alternate" href="/myblog/atom.xml" title="静待花开" type="application/atom+xml">
</head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/myblog/archives/"><div class="headline">文章</div><div class="length-num">57</div></a><a href="/myblog/tags/"><div class="headline">标签</div><div class="length-num">20</div></a><a href="/myblog/categories/"><div class="headline">分类</div><div class="length-num">25</div></a></div><hr class="custom-hr"/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/myblog/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/myblog/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/myblog/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/myblog/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 分享</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/myblog/Gallery/"><i class="fa-fw fas fa-images"></i><span> 照片</span></a></li><li><a class="site-page child" href="/myblog/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/myblog/movies/"><i class="fa-fw fas fa-video"></i><span> 视频</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/myblog/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/myblog/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog-info"><a href="/myblog/" title="静待花开"><span class="site-name">静待花开</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/myblog/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/myblog/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/myblog/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/myblog/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 分享</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/myblog/Gallery/"><i class="fa-fw fas fa-images"></i><span> 照片</span></a></li><li><a class="site-page child" href="/myblog/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/myblog/movies/"><i class="fa-fw fas fa-video"></i><span> 视频</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/myblog/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/myblog/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout" id="content-inner"><div id="post"><div id="post-info"><h1 class="post-title">mysql-index</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2019-11-14T09:26:21.000Z" title="发表于 2019-11-14 17:26:21">2019-11-14</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-09-07T09:44:01.893Z" title="更新于 2023-09-07 17:44:01">2023-09-07</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/myblog/categories/mysql/">mysql</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="mysql-index"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div><article class="post-content" id="article-container"><h1 id="mysql-的索引学习"><a href="#mysql-的索引学习" class="headerlink" title="mysql 的索引学习."></a>mysql 的索引学习.</h1><p><strong>mysql的索引搜索是从最左边的前缀开始的,所以定义索引的列的顺序很重要.</strong></p>
<h2 id="索引类型"><a href="#索引类型" class="headerlink" title="索引类型"></a>索引类型</h2><h3 id="B-Tree-indexes"><a href="#B-Tree-indexes" class="headerlink" title="B-Tree indexes"></a>B-Tree indexes</h3><p>当人们谈论索引没有提及索引类型的时候,基本上都是在谈论B-Tree索引,这种索引使用B-Tree数据结构储存数据.<br>InnoDB存储引擎使用B+Trees.MyISAM存储引擎使用一种前缀表达式技术使得索引更小,但是InnoDB在索引留下了未被压缩的值.<br>MyISAM的索引通过他们的物理存储位置去指向被索引的行,而InnoDB是通过主键值去指向行的.每种形式都有利有弊.</p>
<p>通常B-Tree储存的所有值按顺序存放,每个叶子距离根部的距离都相等.MyISAM使用不同的结构,但主要的都相同.下图抽象展示B-Tree索引的工作情况.<br><img src="/myblog/image/mysql-btree.png"></p>
<p>B-Tree索引之所以能够快速访问数据,是因为存储引擎并没有全表去查找想要的数据.相反的,它在根节点开始(上图中未展示),然后根据节点对子节点的指向寻找.这个指向是根据节点页上我们定义的值为边边界分为大于边界一边和小于边界一边.最终找到或找不到.</p>
<p>现在假定你有下面这个表:</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">CREATE TABLE People ( </span><br><span class="line">	last_name varchar(50) not null, </span><br><span class="line">	first_name varchar(50) not null, </span><br><span class="line">	dob date not null, </span><br><span class="line">	gender enum(&#x27;m&#x27;, &#x27;f&#x27;)not null, </span><br><span class="line">	key(last_name, first_name, dob) </span><br><span class="line">);</span><br></pre></td></tr></table></figure>
<p>可以看出这个表创建了三个索引<code>last_name</code>,<code>first_name</code>,<code>dob</code>.这些索引将包含所有行的这三列的值.接着看看数据库是按上面顺序储存这些值的:<br><img src="/myblog/image/mysql-index-value-order.png"><br>很显然这些索引依据在建表语句中定义的索引列的顺序来排列值的.先根据最先的排若相等,在根据第二个索引排序,一次类推.</p>
<p>查询类型可以使用B-Tree索引.使用全名索引值或索引前缀能够进行高性能查询.仅仅在使用索引的最左前缀查询时是有效的.上面例子定义的索引在下面的查询中是非常有用的高效的:</p>
<ol>
<li>匹配全索引值: 比如上面定义了三个索引,那么我的查询就用三个索引的值去查这个人.</li>
<li>匹配一个最左的前缀:  最左的意思就是按定义索引的顺序第一个索引就是最左的.在例子中最左的是last_name.索引只拿这一个索引去查这个人也是高效的.</li>
<li>匹配一个列前缀: 这个列必须是第一个索引也就是last_name索引.可以以这个索引值<strong>B</strong>开头的进行查找.</li>
<li>匹配一个索引值范围: 也是仅仅用于第一个索引.用于查找last_name的值在Allen和Barrymor范围间的数据.</li>
<li>准确匹配一个部分,另一个部分匹配范围: 例如先定好last_name是Allen,然后第二个匹配项first_name是字符<strong>K</strong>(kim,karl,..),这就是准确匹配第一个索引,范围查找第二个索引</li>
<li>仅索引查询: B树索引通常可以支持仅索引查询，即仅访问索引而不访问行存储的查询。</li>
</ol>
<p>由于tree节点是有序的,因此它既能用于查询,也可以进行分组查询.所以索引对于分组条件是很有用的.</p>
<p>下面说下b-tree索引的限制:</p>
<ol>
<li>如果查询不是从最左的索引列开始查询那这索引就没有用处.</li>
<li>你不能跳过其他的索引列.例如加入你要查一个last_name叫Bill,并且出生日期在一个确定的时间的人.那么这时候索引也没用,因为跳过了第二索引first_name列</li>
<li>存储引擎无法使用第一个范围条件右侧的任何列来优化访问。例如,<strong>WHERE last_name&#x3D;”Smith” AND first_name LIKE ‘J%’ AND dob&#x3D;’1976-12-23’</strong> ,它的索引访问将只使用索引中的前两列,因为<strong>like</strong>是个范围查询,那么右侧的查询条件将起不到优化作用.</li>
</ol>
<h3 id="hash-indexs"><a href="#hash-indexs" class="headerlink" title="hash indexs"></a>hash indexs</h3><p>哈希索引是基于哈希表并且仅对使用索引的列去精准搜索是有效的.对于每一行,存储引擎计算出索引列的哈希码,这个哈希码的值很小并且不同的索引计算出的哈希码值是不同的.在索引中存储哈希码并且在哈希表中有一个对每一行的指向.</p>
<p>在mysql中,仅仅只有内存存储引擎支持显示的哈希索引.对于内存表他们是默认的索引类型,尽管内存表也能有B-Tree类型索引.内存引擎支持非唯一hash索引,这在数据库世界中是不常见的.如果多个值拥有相同的hash码,索引就会在相同的hash表实体中使用链表来存储他们的行指向.下面有个例子:</p>
<figure class="highlight plaintext"><table><tr><td class="code"><pre><span class="line">CREATE TABLE testhash ( </span><br><span class="line">	fname VARCHAR(50) NOT NULL, </span><br><span class="line">	lname VARCHAR(50) NOT NULL,</span><br><span class="line">	KEY USING HASH(fname) </span><br><span class="line">	) ENGINE=MEMORY;</span><br></pre></td></tr></table></figure>
<p>包含的数据:<br>SELECT * FROM testhash; </p>
<table width="100%">
    <tr>
        <th>fname</th>
        <th>lname</th>
    </tr>
    <tr>
        <td>Arjen</td>
        <td>lentz</td>
    </tr>
    <tr>
        <td>Baron</td>
        <td>Schwartz</td>
    </tr>
    <tr>
        <td>Peter</td>
        <td>Zaitsev</td>
    </tr>
    <tr>
        <td>Vadim</td>
        <td>Tkachenko</td>
    </tr>
</table>

<p>现在假设索引使用一个想象的hash方法叫做f(),它可以返回hash值,如下:</p>
<pre><code>f(&#39;Arjen&#39;)= 2323 
f(&#39;Baron&#39;)= 7437 
f(&#39;Peter&#39;)= 8784 
f(&#39;Vadim&#39;)= 2458
</code></pre>
<p>现在索引的数据结构如下:</p>
<table width="100%">
    <tr>
        <th>slot</th>
        <th>value</th>
    </tr>
    <tr>
        <td>2323</td>
        <td>Pointer to row 1</td>
    </tr>
    <tr>
        <td>2458</td>
        <td>Pointer to row 4</td>
    </tr>
    <tr>
        <td>7437</td>
        <td>Pointer to row 2</td>
    </tr>
    <tr>
        <td>8784</td>
        <td>Pointer to row 3</td>
    </tr>
</table>

<p>注意到slot是有序的,但是rows不是.现在我们执行下面这条查询:</p>
<p><strong>SELECT lname FROM testhash WHERE fname&#x3D;’Peter’;</strong></p>
<p>mysql将会计算<q>peter</q>的hash值,并使用这个值在索引中搜索与他匹配的指向.由于f(‘Peter’)&#x3D;8784,mysql将会在索引中找8784并且找到row 3的指向.最后一步是将第三行中的值与<q>peter</q>比较,确定查找到的是正确的.</p>
<p>因为hash索引是非常小,所以一般用哈希索引查询是非常的快.可是也有美中不足,如下:</p>
<ol>
<li><p>因为索引只包含hash码和行指向而没有包含他们的值,mysql不能在索引中使用值来避免对行的读取.所幸的是访问内存中的行是非常快的,因此通常hash索引不会降级使用,也就是说一般就在内存存储引擎中使用.</p>
</li>
<li><p>mysql无法使用hash索引去排序,因为hash索引并没有按照顺序存储行(rows) 		</p>
</li>
<li><p>hash索引不支持部分索引匹配.因为他们是从一个完整的索引值去计算hash值的.如果你有一个索引是(A,B),然后你的查询条件仅仅是A,那么这个索引将失去作用.</p>
</li>
<li><p>hash索引只支持等式的比较,如**&#x3D;,IN(),&lt;&#x3D;&gt;,<strong>操作.他们不能在范围查询中快速查询,例如</strong>where price &gt; 100**</p>
</li>
<li><p>在hash索引中访问数据是非常快的,除非存在很多hash冲突.当碰撞发生,存储引擎必须在冲突的指向处后面附加一个链表去存储冲突的行指向,然后比较他们的值和查找到的值去找到正确的行.</p>
</li>
<li><p>如果有太多冲突,那么索引的维护操作将会很慢.</p>
</li>
</ol>
<p>InnoDB存储引擎有个特性叫做<em>adaptive hash indexes</em>.就是当InnoDB发现一些索引值被频繁的访问,它就会在B-Tree索引树的上方的内存中为那些索引值建立hash索引.这将会使得B-Tree索引拥有一些hash索引的特性,例如非常快速的hash查找.这个过程是完全自动的,你不能控制和配置它,但是你可以完全关闭<em>adaptive hash indexes</em>这个特性.</p>
<p><strong>建立你自己的hash索引</strong></p>
<p>如果你的存储引擎不支持hash索引,你可以以InnoDB使用的方式模拟他们.它将让你以hash索引的特性去访问.比如,对一个很长的key建立一个很小的hash索引.</p>
<p>你可以这么做.在一个标准的B-Tree索引的顶部创建一个伪hash索引.这和真正的hash索引并不完全一样,因为它仍讲使用B-Tree索引去查询.然而,他将使用key的hash值去查找,而不是key值本身.你只需要在查询条件中手动指定一个hash方法.</p>
<p>一个查找URL的hash方法正确执行的例子.通常URL作为索引列会导致B-Tree索引变得很大,因为他们太长了.你的查询一般就像下面这样:<br><code>SELECT id FROM url WHERE url=&quot;http://www.mysql.com&quot;;</code><br>但是当你在这表中移除url的索引列并且添加一个<strong>url_crc</strong>索引列,你的查询可以像下面这样:<br><code>SELECT id FROM url WHERE url=&quot;http://www.mysql.com&quot; AND url_crc=CRC32(&quot;http://www.mysql.com&quot;);</code><br>CRC32()这是mysql系统自带的方法,这样性能更好,因为mysql的查询优化会知道去选择一个更小更高效的索引,那就是<strong>url_crc</strong>列的索引.CRC32方法就是把值转成hash码,在这里它使用值为1560514994的索引去查找实体.即使一些行有相同的<strong>url_crc</strong>值,使用整型快速比较也是很容易找出那些行的,然后验证那些找出的行是否匹配完整的URL.</p>
<p>有个不利点就是这个方法是需要去维护hash值的.你可以使用触发器triggers.接下来的例子会展示当你插入或更新时触发器是怎样帮助维护<strong>url_crc</strong>索引列的.首先创建一个表:</p>
<pre><code>CREATE TABLE pseudohash ( 
    id int unsigned NOT NULL auto_increment, 
    url varchar(255) NOT NULL, 
    url_crc int unsigned NOT NULL DEFAULT 0, 
    PRIMARY KEY(id) 
);
</code></pre>
<p>现在,我们来创建一个触发器.使用一个临时的定界符<code>//</code>来划分不同的触发器语句.使用分号作为触发器里的定界符</p>
<pre><code>DELIMITER //
CREATE TRIGGER pseudohash_crc_ins BEFORE INSERT ON pseudohash FOR EACH ROW BEGIN 
SET NEW.url_crc=crc32(NEW.url); 
END;
//
CREATE TRIGGER pseudohash_crc_upd BEFORE UPDATE ON pseudohash FOR EACH ROW BEGIN 
SET NEW.url_crc=crc32(NEW.url); 
END;
//
DELIMITER ;
</code></pre>
<p>剩下的就是验证下触发器维护的这个hash值OK不.</p>
<p><code>INSERT INTO pseudohash (url) VALUES (&#39;http://www.mysql.com&#39;);</code><br><code>SELECT * FROM pseudohash;</code></p>
<table width="100%">
    <tr>
        <th>id</th>
        <th>url</th>
        <th>url_crc</th>
    </tr>
    <tr>
        <td>1</td>
        <td>http://www.mysql.com</td>
        <td>1560514994</td>
    </tr>
</table>

<p>如果你使用这个方法(crc32),那么你就不应该使用**SHA1()<strong>或者</strong>MD5()**的hash方法.这些方法返回非常长的字符串,这样会很浪费空间从而导致更慢的比较.他们是密码学上的强方法被设计于完全消除冲突,这不是你这里的目标.简单的hash方法有更好的性能同时也会提高冲突率.</p>
<p>如果你的表有许多行并且**CRC32()<strong>方法带来太多的冲突,那么可以实现你自己的64位hash方法.要确保你的方法返回一个整数而不是字符串.一种实现办法是通过</strong>MD5()**方法仅仅返回它值的一部分.这样比你以自己的方式写一个自定义方法相比可能效率低下,但是你自己写可能会遇到困难.</p>
<p><code>SELECT CONV(RIGHT(MD5(&#39;http://www.mysql.com/&#39;), 16), 16, 10) AS HASH64;</code></p>
<p>HASH64 &#x3D; 9761173720318281581</p>
<p><strong>处理hash冲突</strong></p>
<p>当你通过hash索引值去搜索,你也必须在你的查询条件中包含文本值:</p>
<pre><code>SELECT id FROM url WHERE url_crc=CRC32(&quot;http://www.mysql.com&quot;)
AND url=&quot;http://www.mysql.com&quot;;
</code></pre>
<p>下面这个查询可能会不正确,因为如果另一个URL的hash值也是一样,那么查询会出现两个结果:</p>
<pre><code>SELECT id FROM url WHERE url_crc=CRC32(&quot;http://www.mysql.com&quot;);
</code></pre>
<p>hash冲突可能会比你想象的增长的更快,由于所谓的生日悖论.**crc32()<strong>返回一个32位的整数值,因此当总索引值个数少至93000的时候,冲突率可能会达到1%.所以为了避免冲突你必须使用两个条件来进行hash索引查询.你也可以使用</strong>FNV64()**方法,这方法由Percona Server托管,可以下载作为mysql的一个插件从而使用它.它是64位长度,非常快,并且比src32的冲突率低</p>
<p><strong>索引的三条直接好处</strong></p>
<ol>
<li>索引减少服务扫描检查表的数据量</li>
<li>索引帮助服务避免排序和建临时表</li>
<li>索引把随机I&#x2F;O转变成序列I&#x2F;O</li>
</ol>
<h2 id="高性能的索引策略"><a href="#高性能的索引策略" class="headerlink" title="高性能的索引策略"></a>高性能的索引策略</h2><h3 id="隔离列"><a href="#隔离列" class="headerlink" title="隔离列"></a>隔离列</h3><p>通常我们的查询语句会中断或阻止MYsql使用可用的索引.一般的mysql不能在列上使用索引,除非列在查询中被隔离了.<q>Isolating</q>隔离列意味着它不是这个表达式的一部分或者在这个查询中的方法里面.</p>
<p>下面这例子,查询不能在<strong>actor_id</strong>上使用索引:</p>
<pre><code>SELECT actor_id FROM sakila.actor WHERE actor_id + 1 = 5;
</code></pre>
<p>人可以很容易知道where条件是actor_id&#x3D;4这个等式,但是mysql不能理解这方程式中的actor_id+1.<strong>你应该要把索引列单独的放到比较操作的一边.</strong></p>
<p>这里还有一种普遍错误用法:</p>
<pre><code>SELECT ... WHERE TO_DAYS(CURRENT_DATE) - TO_DAYS(date_col) &lt;= 10;
</code></pre>
<h3 id="前缀索引和索引选择"><a href="#前缀索引和索引选择" class="headerlink" title="前缀索引和索引选择"></a>前缀索引和索引选择</h3><p>索引的选择性是不同索引值的数量和表中所有行的数量之比.高选择率的索引当然非常好,因为这能让mysql查询匹配的时候过滤掉很多行.一个唯一的索引值(unique index)的选择率是1(最高).</p>
<p>列的前缀经常被选择用来提高性能,如果你对<strong>BLOB</strong>或者<strong>TEXT</strong>或很长的<strong>varchar</strong>列建立索引,你必须定义索引前缀,因为mysql不允许用完整长度索引他们.</p>
<p>策略是应该选择足够长的前缀那么即使你对所有列都建立索引该索引一样的有用.足够长的前缀唯一性就越高,那么选择性就高.</p>
<p>为了找出最好的前缀长度,你应该找出一列最频繁的值并且把这列值与一列最频繁的前缀进行比较.下面通过例子演示找最佳前缀长度</p>
<p>假设你有个city表.里面有写城市的数据,然后进行下面的操作:</p>
<pre><code>CREATE TABLE sakila.city_demo(city VARCHAR(50) NOT NULL);
INSERT INTO sakila.city_demo(city) SELECT city FROM sakila.city;
//重复5次
INSERT INTO sakila.city_demo(city) SELECT city FROM sakila.city_demo;
//然后随机分布
UPDATE sakila.city_demo SET city = (SELECT city FROM sakila.city ORDER BY RAND() LIMIT 1);
</code></pre>
<p>有了表,然后我们开始以全名查询城市出现的次数,这就是一个阈值的意思,后面根据前缀查的次数接近这阈值就好了.</p>
<pre><code>SELECT COUNT(*) AS cnt, city
    FROM sakila.city_demo GROUP BY city ORDER BY cnt DESC LIMIT 10;
</code></pre>
<table width="100%">
    <tr>
        <th>cnt</th>
        <th>city</th>
    </tr>
    <tr>
        <td>65</td> //出先次数越多唯一性越差
        <td>london</td>
    </tr>
    <tr>
        <td>49</td>
        <td>Hiroshima</td>
    </tr>
    <tr>
        <td>48</td>
        <td>Teboksary</td>
    </tr>
</table>

<p>现在得到了唯一性最高的时候city出现的次数,接着我们以名字的前7个位字符统计出现次数:</p>
<pre><code>SELECT COUNT(*) AS cnt, LEFT(city, 7) AS pref 
FROM sakila.city_demo GROUP BY pref ORDER BY cnt DESC LIMIT 10;
</code></pre>
<table width="100%">
    <tr>
        <th>cnt</th>
        <th>pref</th>
    </tr>
    <tr>
        <td>70</td>
        <td>santiag</td>
    </tr>
    <tr>
        <td>68</td>
        <td>san Fel</td>
    </tr>
    <tr>
        <td>65</td>
        <td>london</td>
    </tr>
</table>

<p>出现的次数越高说明唯一性越查,那么就是选择性越差.<br>这个和前面全名查出现的次数差不多就是<strong>最合适的前缀长度</strong>,找出了合适的前缀长度那么最后建立前缀索引:</p>
<pre><code>ALTER TABLE sakila.city_demo ADD KEY (city(7));
</code></pre>
<p>当然也可以用上面哪个公式去找最适长度前缀,代码如下,选比值最大的:</p>
<pre><code>SELECT COUNT(DISTINCT LEFT(city, 3))/COUNT(*) AS sel3, 
COUNT(DISTINCT LEFT(city, 4))/COUNT(*) AS sel4, 
COUNT(DISTINCT LEFT(city, 5))/COUNT(*) AS sel5, 
COUNT(DISTINCT LEFT(city, 6))/COUNT(*) AS sel6, 
COUNT(DISTINCT LEFT(city, 7))/COUNT(*) AS sel7 
FROM sakila.city_demo;
</code></pre>
<h3 id="多列索引"><a href="#多列索引" class="headerlink" title="多列索引"></a>多列索引</h3><p>多列索引常常很难理解.普遍存在很多错误.下面把这些错误一个一个说明:</p>
<p><strong>单独的建立多个索引列:</strong></p>
<pre><code>    CREATE TABLE t (
        c1 INT, 
        c2 INT, 
        c3 INT, 
        KEY(c1), 
        KEY(c2), 
        KEY(c3) 
    );
</code></pre>
<p>许多列上的单独索引不会帮助MySQL提高大多数查询的性能.<br>但是在mysql5版本以上有个<em>index merge</em>的策略可以限制从单表到目标行位置多索引的使用.假如你要进行下面的查询:</p>
<pre><code>    SELECT film_id, actor_id FROM sakila.film_actor 
    WHERE actor_id = 1 OR film_id = 1;
</code></pre>
<p>actor_id和film_id是两个单独的列索引,在低于mysql5版本中,这语句会产生全表扫描.应该使用<strong>union</strong>来连接两个查询如下:</p>
<pre><code>    SELECT film_id, actor_id FROM sakila.film_actor WHERE actor_id = 1
    UNION ALL
    SELECT film_id, actor_id FROM sakila.film_actor WHERE film_id = 1
    AND actor_id &lt;&gt; 1;
</code></pre>
<p>在mysql5以上版本,查询会使用两个索引同步扫描他们并且合并结果.这样的策略有三个变量:<strong>union</strong>对于<strong>OR</strong>条件,<strong>intersection</strong>对于<strong>AND</strong>条件,unions of intersection 对于两者的结合.所以mysql5以上可以直接用OR那些条件,它会自动转成上面代码的形式查询.</p>
<p><em>index merge</em>策略虽好,也有不足:</p>
<ol>
<li><p>当服务用的是交叉索引也就是AND条件时,这通常意味着你需要带有全部相关列的单独索引,而不是必须合并的多索引.</p>
</li>
<li><p>当服务用OR条件时,有时算法的缓冲,排序,合并操作会占用太多CPU和内存资源.有一个真相是,假如所有的索引没有很高的选择性,意味着唯一性低,那么出现次数多,那么扫描返回大量的行去操作合并.</p>
</li>
<li><p>优化器并没有考虑这笔性能开销，它只是优化了随机页面读取的次数.它可能比纯表扫描运行得慢。大量的内存和CPU使用率也往往会影响并发查询.有时，使用UNION重写此类查询更为理想，而UNION是您以前在MySQL 4.1及更早版本中必须执行的方式。</p>
</li>
</ol>
<p>你可以使用<strong>optimizer_switch</strong>选项或变量关闭index merges策略.也可以使用<strong>IGNORE INDEX</strong></p>
<h3 id="选择好列顺序"><a href="#选择好列顺序" class="headerlink" title="选择好列顺序"></a>选择好列顺序</h3><p>正确的列顺序依赖查询时候使用的索引,你必须考虑怎么选择索引的顺序以便以一种对查询有利的方式进行分组,排序.</p>
<p>列顺序对于多列索引来说是非常重要的.选择列顺序有个旧的经验法则:将选择性最高的列置于索引的第一位.在一些案例中这样做是很有帮助的,但是在考虑所有情况下,通常比起随机I&#x2F;O和排序显得没那么重要.</p>
<p>在不考虑分组和排序的情况下将选择性最高的列置于索引的第一位是个非常好的想法,这样索引的目的就仅仅只是优化where查询条件了.</p>
<h2 id="聚簇索引-Clustered-Indexes"><a href="#聚簇索引-Clustered-Indexes" class="headerlink" title="聚簇索引(Clustered Indexes)"></a>聚簇索引(Clustered Indexes)</h2><p>聚簇索引并不是单独的索引类型.相反,他们是对数据存储的一种方法.但是在InnoDB的聚簇索引实际上就是存储一个B-Tree索引和相同结构上的行.</p>
<p>当一个表具有一个聚簇索引,那么他的行实际上被存储在索引的叶子页上.“Clustered”一词是指具有相邻键值的行彼此靠近存储的事实。每个表只能有一个聚簇索引，因为您不能一次将行存储在两个位置。但是，<em>covering indexes</em>使您可以模拟多个聚簇索引</p>
<p>由于存储引擎对于索引的实现是响应式的,并不是所有的存储引擎都支持聚簇索引.</p>
<p>一些数据库服务让你自己选择聚簇索引,但是mysql不是这样的.InnoDB是通过主键来聚集数据的</p>
<p>如果你不想定义主键,InnoDB将会尝试使用一个唯一的非空索引替换.如果没有这样的一个索引,那么InnoDB将会为你定义一个隐藏的主键然后聚集数据.InnoDB聚簇索引一起记录在一个页中.页是带有相邻键值,他们之间可能存在一些距离.</p>
<p>一个聚簇主键可以提高性能,但是也能导致一系列性能问题.因此,使用它要好好考虑.</p>
<p>下图展示了聚簇索引是如何放置的.注意叶子页包含整行但是节点页仅仅包含索引列,在这个案例中,索引行是一个整数值.<br><img src="/myblog/image/mysql-cluster-indexes.png"></p>
<p><strong>聚簇索引的优势:</strong></p>
<ol>
<li><p>您可以将相关数据保持在一起。例如，在实现邮箱时，您可以按user_id进行聚簇，这样就可以通过从磁盘中仅获取几个页面来检索单个用户的所有邮件。如果您不使用聚簇，则每条消息可能都需要自己的磁盘I&#x2F;O。</p>
</li>
<li><p>数据访问非常快.一个聚簇索引讲索引和数据一起装进B-Tree里,因此从一个聚簇索引中检索行比在一个没有聚簇索引中的比较检索相对更快一些.</p>
</li>
<li><p>使用覆盖索引的查询能够使用在叶子节点中被包含的主键值.</p>
</li>
</ol>
<p>如果你采用他们的优势去设计表和查询,那么这些优势可以极大的提升性能.然后聚簇索引也有一些缺点:</p>
<ol>
<li>聚簇索引极大的提高了I&#x2F;O绑定工作负载.如果数据适合存储在内存中，那么访问顺序并不重要,因此聚簇在此情况下不会带来太多好处</li>
<li>插入速度非常依赖于插入区的顺序.在以主键排序的表中插入行能够非常快速的把数据加载到一个InnoDB表中.如果你不在以主键排序的表中加载行,在加载大量数据之后使用<strong>OPTIMIZE TABLE</strong>去识别表可能会是一种很好的方式.</li>
<li>更新聚簇索引列是非常消耗性能的,因为他会强迫InnoDB去移动每一个已更新的行到一个新位置.</li>
<li>当插入新行或更新行的主键以致必须移动该行时，基于聚簇索引的表可能会进行页面拆分.当一个行的键值表示这行必须放置在一个充满数据的页的时候,页面拆分就会发生.存储引擎必须将一个页划分为两个才能容纳这个行.页划分将会导致一个表使用更多的硬盘空间.</li>
<li>聚簇表的全表扫描更慢,特别是如果由于页面拆分而导致行的密集程度较低或不按顺序存储时。</li>
<li>二级（非聚集）索引可能比您预期的要大，因为它们的叶节点包含引用行的主键列。</li>
<li>二级索引访问需要两个索引查询.</li>
</ol>
<p>为什么二级索引就需要两个索引搜索? 记住: 一个叶子节点不会存储一个引用行的物理存储位置的指向器;反之,它存储的是行的主键值.</p>
<p>这就意味着,从一个二级索引去查找一行,存储引擎首先在二级索引中找到叶子节点,然后将主键值存储在那里,通过主键导航,查找对应的行.</p>
<p><strong>InnoDB和MyISAM的数据位置</strong></p>
<p>用下面这个表做演示:</p>
<pre><code>CREATE TABLE layout_test ( 
    col1 int NOT NULL, 
    col2 int NOT NULL, 
    PRIMARY KEY(col1), 
    KEY(col2) 
);
</code></pre>
<p>假设这个表里有1到10000的主键值,以随机顺序插入然后使用<strong>OPTIMIZE TABLE</strong>来优化.换句话说,数据在硬盘获得最佳整理,但是行可能会是随机顺序的.<strong>col2</strong>的值被设计为1到100的随机数,因此会有很多重复数.</p>
<p><strong>MyISAM</strong>的数据分布.</p>
<p>MyISAM的数据分布更简单,MyISAM以他们的插入顺序为顺序在硬盘上存储行.如下图所示:<br><img src="/myblog/image/MyISAM-data-layout.png"></p>
<p>在每行边上展示了以0开头的行号.因为这个行是固定大小的,所以MyISAM能够通过从表单的开始行找到所需要的位数字.(MyISAM并不总是使用行号) 它根据行的大小是否是固定的还是变化的来决定使用不同的策略.</p>
<p>这中布局让它很容易建立索引.每个索引中的叶子节点仅仅只能包含行号.下图是主键在表中分布图:<br><img src="/myblog/image/MyISAM-data-primary-layout.png"></p>
<p><strong>col2</strong>列索引和其他索引一样没什么特别的.事实上在MyISAM中主键和其他键在结构上没有什么不同.主键仅仅是唯一,非空的索引被称为主键.</p>
<p><strong>InnoDB</strong>的数据分布</p>
<p>InnoDB以差异很大的方式存储相同的数据,这是由于它的聚簇组织.如下图所示:<br><img src="/myblog/image/InnoDB-data-layout.png"></p>
<p>咋一看好像没啥大区别.但是仔细一看,你会注意到这个图例展示了整个表,不单单是索引.因为聚簇索引在InnoDB中<q>就是</q>表.没有像MyISAM一样使用行号划分.</p>
<p>二级索引也不一样.InnoDB的二级索引不包含行指向器,而是包含主键值,这个值扮演指向器指向对应行.当行移动或者数据也划分的时候这种策略将会减少二级索引的维护工作.使用行的主键值作为指向器使得索引变的更大,但也意味着InnoDB移动行的时候不用在更新指向器了<br><img src="/myblog/image/InnoDB-data-secondry-layout.png"></p>
<p>这是B-Tree的叶子节点插图,这里有意的删除了关于非叶子节点的细节.InnoDB每个非叶子节点包含索引列和下一层级节点的指向器.</p>
<p><strong>InnoDB中以主键顺序插入行</strong></p>
<p>如果你使用的是InnoDB,那么可以不用特意指定聚簇索引,服务会自动定义一个替代键作为主键,它的值不是从你的应用数据中获得的.最早的时候是使用<strong>AUTO_INCREAMENT</strong>列来做的.这样会确保行的插入会以顺序插入并且会增加主键的使用来提升性能.</p>
<p>这是最好的方式去避免随机聚簇键,尤其是I&#x2F;O绑定负载.例如使用UUID值从性能这点来说就不是个好选择.它使得聚簇索引随机插入,这是非常糟糕的情况,这对于数据的聚集没有任何帮助.</p>
<p>由于主键值是连续的，因此InnoDB在前一个记录之后立即存储每个记录。当页面达到最大填充因子时（InnoDB的初始填充因子仅为15&#x2F;16满，以留出以后修改的空间），下一条记录将进入新页面。一旦以这种顺序的方式加载了数据，主键页几乎就被按顺序记录打包了，这是非常需要的。</p>
<p><strong>UUID</strong>对性能的坏处总结:</p>
<ol>
<li>目标页面可能已刷新到磁盘并从缓存中删除,或者甚至可能从来没有放置到缓存中,在这种情况下,在插入一个新行之前InnoDB将不得不从硬盘查找和读取它.这就会导致大量随机I&#x2F;O.</li>
<li>当不按顺序插入,InnoDB不得不频繁的划分页来为新行分配空间.这就要求在移动大量数据并且至少修改三页而不是一页.</li>
<li>由于页的划分使得页变得很分散且毫无规律的排布,因此最终数据是片段化的</li>
</ol>
<p>总结就是:<strong>使用InnoDB的时候尽量使用有序主键做聚簇索引!</strong></p>
<p><strong>有序主键发生错误</strong></p>
<p>在高并发的情况下,按主键顺序插入实际上可以在InnoDB中创建竞争点。主键的高端是一个热点。因为所有插入都在此处进行，所以并发插入可能会争夺下一个键锁定.另一个热点是<strong>AUTO_INCREMENT</strong>锁定机制。如果在这方面遇到问题,可以重新设计表或应用或配置innodb_autoinc_lock_mode属性.</p>
<h2 id="覆盖索引-Covering-Indexes"><a href="#覆盖索引-Covering-Indexes" class="headerlink" title="覆盖索引(Covering Indexes)"></a>覆盖索引(Covering Indexes)</h2><p>普遍的建议就是为查询的where条件的列建立索引,但是这只是查询中的一种.索引需要被设计满足当下所有查询,不单单是where条件.索引确实是高效找出行的方式,但是mysql也能使用索引去检索列的数据,因此它不需要读所有的行.毕竟索引的叶子节点包含着索引列的值.一个索引覆盖了满足一个查询需求的所有数据称为覆盖索引</p>
<p>覆盖索引是一个非常强大的工具,能够极大的提升性能.只考虑读索引而不是读数据的好处如下:</p>
<ol>
<li>索引实体通常比整行占的内存更小,因此如果仅仅读取索引,mysql能够读取的数据就小的多.这对于缓存负载是非常重要的,在缓存负载中有很多来自数据复制的响应次数.对I&#x2F;O绑定负载也是很有帮助的,因为索引比数据更小能够更好的适应内存.</li>
<li>索引是按照他们的索引值进行排序的,因此与从一个随机硬盘位置获取每一行相比I&#x2F;O绑定访问范围将不需要太多I&#x2F;O.例如MyISAM,你甚至可以优化表去获得完整有序索引,这能让一些简单范围查询使用完整有序索引访问.</li>
<li>例如MyISAM,仅仅只有索引缓存在mysql内存中.因为操作系统为MyISAM缓存数据，所以访问它通常需要系统调用。这可能会对性能产生巨大影响，尤其是对于缓存的工作负载，其中系统调用是数据访问中最消耗性能的部分。</li>
<li>由于InnoDB的聚簇索引，覆盖索引对于InnoDB表特别有用。InnoDB的二级索引将行的主键值保存在其叶节点处。因此，覆盖查询的二级索引可以避免在主键中进行另一个索引查找</li>
</ol>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="https://zhangbo4881820.gitee.io/myblog">brad 随风起舞</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://zhangbo4881820.gitee.io/myblog/posts/17440/">https://zhangbo4881820.gitee.io/myblog/posts/17440/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://zhangbo4881820.gitee.io/myblog" target="_blank">静待花开</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/myblog/tags/mysql/">mysql</a></div><div class="post_share"><div class="social-share" data-image="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/social-share.js/1.0.16/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdnjs.cloudflare.com/ajax/libs/social-share.js/1.0.16/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/myblog/posts/34744/" title="计算机的基本组成(第一天)"><div class="cover" style="background: var(--default-bg-color)"></div><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">计算机的基本组成(第一天)</div></div></a></div><div class="next-post pull-right"><a href="/myblog/posts/15484/" title="html-study-04"><div class="cover" style="background: var(--default-bg-color)"></div><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">html-study-04</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/myblog/posts/15095/" title="mysqlCookBook01"><div class="cover" style="background: var(--default-bg-color)"></div><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2019-11-25</div><div class="title">mysqlCookBook01</div></div></a></div><div><a href="/myblog/posts/15287/" title="mysqlCookBook02"><div class="cover" style="background: var(--default-bg-color)"></div><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2019-11-26</div><div class="title">mysqlCookBook02</div></div></a></div><div><a href="/myblog/posts/64374/" title="mysqlCookBook03"><div class="cover" style="background: var(--default-bg-color)"></div><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2019-11-27</div><div class="title">mysqlCookBook03</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png" onerror="this.onerror=null;this.src='/myblog/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">brad 随风起舞</div><div class="author-info__description">有些事情需要一辈子的沉淀</div></div><div class="card-info-data site-data is-center"><a href="/myblog/archives/"><div class="headline">文章</div><div class="length-num">57</div></a><a href="/myblog/tags/"><div class="headline">标签</div><div class="length-num">20</div></a><a href="/myblog/categories/"><div class="headline">分类</div><div class="length-num">25</div></a></div><a id="card-info-btn" href="https://github.com/xxxxxx"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/xxxxx" target="_blank" title="Github"><i class="fab fa-github" style="color: #24292e;"></i></a><a class="social-icon" href="mailto:xxxxxx@gmail.com" target="_blank" title="Email"><i class="fas fa-envelope" style="color: #4a7dbe;"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">This is my Blog</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#mysql-%E7%9A%84%E7%B4%A2%E5%BC%95%E5%AD%A6%E4%B9%A0"><span class="toc-number">1.</span> <span class="toc-text">mysql 的索引学习.</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%B4%A2%E5%BC%95%E7%B1%BB%E5%9E%8B"><span class="toc-number">1.1.</span> <span class="toc-text">索引类型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#B-Tree-indexes"><span class="toc-number">1.1.1.</span> <span class="toc-text">B-Tree indexes</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#hash-indexs"><span class="toc-number">1.1.2.</span> <span class="toc-text">hash indexs</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%AB%98%E6%80%A7%E8%83%BD%E7%9A%84%E7%B4%A2%E5%BC%95%E7%AD%96%E7%95%A5"><span class="toc-number">1.2.</span> <span class="toc-text">高性能的索引策略</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%9A%94%E7%A6%BB%E5%88%97"><span class="toc-number">1.2.1.</span> <span class="toc-text">隔离列</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%89%8D%E7%BC%80%E7%B4%A2%E5%BC%95%E5%92%8C%E7%B4%A2%E5%BC%95%E9%80%89%E6%8B%A9"><span class="toc-number">1.2.2.</span> <span class="toc-text">前缀索引和索引选择</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%A4%9A%E5%88%97%E7%B4%A2%E5%BC%95"><span class="toc-number">1.2.3.</span> <span class="toc-text">多列索引</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%80%89%E6%8B%A9%E5%A5%BD%E5%88%97%E9%A1%BA%E5%BA%8F"><span class="toc-number">1.2.4.</span> <span class="toc-text">选择好列顺序</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%81%9A%E7%B0%87%E7%B4%A2%E5%BC%95-Clustered-Indexes"><span class="toc-number">1.3.</span> <span class="toc-text">聚簇索引(Clustered Indexes)</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%A6%86%E7%9B%96%E7%B4%A2%E5%BC%95-Covering-Indexes"><span class="toc-number">1.4.</span> <span class="toc-text">覆盖索引(Covering Indexes)</span></a></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/myblog/posts/15695/" title="jenkins（1）">jenkins（1）</a><time datetime="2023-09-14T02:17:44.000Z" title="发表于 2023-09-14 10:17:44">2023-09-14</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/myblog/posts/22012/" title="wsl的Ubuntu子系统（1）">wsl的Ubuntu子系统（1）</a><time datetime="2023-09-13T08:42:19.000Z" title="发表于 2023-09-13 16:42:19">2023-09-13</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/myblog/posts/30302/" title="effective-java-(接口优于抽象类)">effective-java-(接口优于抽象类)</a><time datetime="2023-09-12T08:12:48.000Z" title="发表于 2023-09-12 16:12:48">2023-09-12</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/myblog/posts/9473/" title="effective-java(创建和销毁对象--组合的形式优于继承)">effective-java(创建和销毁对象--组合的形式优于继承)</a><time datetime="2023-09-11T08:23:19.000Z" title="发表于 2023-09-11 16:23:19">2023-09-11</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/myblog/posts/16107/" title="Hello World">Hello World</a><time datetime="2023-09-07T09:44:01.910Z" title="发表于 2023-09-07 17:44:01">2023-09-07</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2023 By brad 随风起舞</div><div class="framework-info"><span>框架 </span><a href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/myblog/js/utils.js"></script><script src="/myblog/js/main.js"></script><script src="/myblog/js/fancybox.umd.js"></script><div class="js-pjax"></div><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div class="no-result" id="local-search-results"></div><div id="local-search-stats-wrap"></div></div></div><div id="search-mask"></div><script src="/myblog/js/search/local-search.js"></script></div></div></body></html>